package main

import (
	"errors"
	//"strconv"

	"hedge/persistence"
)

type OrderPositionState int
type OrderState int
type OrderSubState int

const (
	PositionState_Unknown OrderPositionState = iota
	PositionState_NotPosition
	PositionState_Position
)

const (
	State_Unknow OrderState = iota // 未知状态，仅在程序启动时使用

	// 固定状态
	State_NotPosition // 未持仓状态，没有套利持仓
	State_Position    // 持仓状态

	// 中间状态
	State_OneCanCreatePosition  // 某个交易对符合开仓条件
	State_OneCanClosePosition   // 某个交易对符合平仓条件
	State_LimitOrderCreated     // 开仓，套利限价单已经下发，尚未判断是否成交
	State_AntiLimitOrderCreated // 平仓，套利限价单已经下发，尚未判断是否成交
)

const (
	SubState_Init OrderSubState = iota // 最初状态

	// 现货先成交的序列
	SubState_BinanceAntiCreated  // 现货成交后，合约尚未成交，现货反向单创建完成
	SubState_BinanceAntiComplete // 现货反向单成交，合约单撤销

	// 合约先成交的序列
	SubState_FuturesAntiCreated  // 合约成交后，现货尚未成交，合约反向单创建完成
	SubState_FuturesAntiComplete // 合约反向单成交，现货单撤销

	// 正常最终状态
	SubState_NormalComplete // 正常情况现货和合约成交
)

type StateMachine struct {
	arbitrage *SymbolArbitrage

	PositionState OrderPositionState
	State         OrderState
	SubState      OrderSubState
}

func (sm *StateMachine) ChangeState(state OrderState, opts ...interface{}) (err error) {
	// 1.判断当前状态和传入的状态，是否符合变更规范
	if state == State_Unknow { // 不可传入State_Unknow
		err = errors.New("Cannot change state to unknow")
		return
	}
	if sm.State == State_Unknow {
		if state != State_NotPosition && state != State_Position { // 这两种属于固定状态，程序必须从未知状态先走向固定状态
			err = errors.New("Cannot change state from unknow to semistate")
			return
		}
	} else {
		if sm.State == State_NotPosition {
			if state == State_AntiLimitOrderCreated || state == State_OneCanClosePosition {
				err = errors.New("State change illegal")
				return
			}
		} else if sm.State == State_Position {
			if state == State_LimitOrderCreated || state == State_OneCanCreatePosition {
				err = errors.New("State change illegal")
				return
			}
		} else if sm.State == State_LimitOrderCreated {
			if state == State_AntiLimitOrderCreated {
				err = errors.New("State change illegal")
				return
			}
		} else if sm.State == State_AntiLimitOrderCreated {
			if state == State_LimitOrderCreated {
				err = errors.New("State change illegal")
				return
			}
		}
	}
	if state == State_OneCanCreatePosition {
		if sm.State != State_NotPosition && sm.State != State_OneCanCreatePosition {
			err = errors.New("State change illegal")
			return
		}
	} else if state == State_OneCanClosePosition {
		if sm.State != State_Position && sm.State != State_OneCanClosePosition {
			err = errors.New("State change illegal")
			return
		}
	} else if state == State_LimitOrderCreated {
		if sm.State != State_OneCanCreatePosition {
			err = errors.New("State change illegal")
			return
		}
	} else if state == State_AntiLimitOrderCreated {
		if sm.State != State_OneCanClosePosition {
			err = errors.New("State change illegal")
			return
		}
	}

	Info.Printf("Change State from %v to %v\n", sm.State, state)
	Info.Println(opts...)

	// 2.正式变更状态
	if state == State_NotPosition {
		err = sm.changeState2NotPosition()
	} else if state == State_Position {
		if len(opts) < 1 {
			err = errors.New("opts length illegal")
			return
		}
		position := opts[0].(persistence.ArbitragePosition)
		err = sm.changeState2Position(position)
	} else if state == State_OneCanCreatePosition {

	} else if state == State_OneCanClosePosition {

	} else if state == State_LimitOrderCreated {
		if len(opts) < 2 {
			err = errors.New("opts length illegal")
			return
		}
		binanceOrderId := opts[0].(int64)
		futuresOrderId := opts[1].(int64)
		err = sm.changeState2LimitOrderCreated(binanceOrderId, futuresOrderId)
	} else if state == State_AntiLimitOrderCreated {
		if len(opts) < 2 {
			err = errors.New("opts length illegal")
			return
		}
		binanceOrderId := opts[0].(int64)
		futuresOrderId := opts[1].(int64)
		err = sm.changeState2AntiLimitOrderCreated(binanceOrderId, futuresOrderId)
	}

	sm.State = state
	//sm.SubState = SubState_Init
	err = sm.ChangeSubState(SubState_Init)

	return
}

func (sm *StateMachine) ChangeSubState(state OrderSubState, opts ...interface{}) (err error) {
	Info.Printf("Change SubState from %v to %v\n", sm.SubState, state)
	Info.Println(opts...)
	if state == SubState_Init {
		sm.arbitrage.binanceAntiLimitOrderId = 0
		sm.arbitrage.futuresAntiLimitOrderId = 0
		sm.arbitrage.subStateBinanceExecQty = 0.0
		sm.arbitrage.subStateBinanceExecPrice = 0.0
		sm.arbitrage.subStateFuturesExecQty = 0.0
		sm.arbitrage.subStateFuturesExecPrice = 0.0
	} else if state == SubState_BinanceAntiCreated {
		if len(opts) < 3 {
			err = errors.New("opts length illegal")
			return
		}
		sm.arbitrage.binanceAntiLimitOrderId = opts[0].(int64)
		sm.arbitrage.futuresAntiLimitOrderId = opts[1].(int64)
		sm.arbitrage.subStateBinanceExecQty = opts[2].(float64)
		sm.arbitrage.subStateBinanceExecPrice = opts[3].(float64)
		sm.arbitrage.subStateFuturesExecQty = 0.0
		sm.arbitrage.subStateFuturesExecPrice = 0.0
	} else if state == SubState_FuturesAntiCreated {
		if len(opts) < 2 {
			err = errors.New("opts length illegal")
			return
		}
		sm.arbitrage.binanceAntiLimitOrderId = opts[0].(int64)
		sm.arbitrage.futuresAntiLimitOrderId = opts[1].(int64)
		sm.arbitrage.subStateBinanceExecQty = 0.0
		sm.arbitrage.subStateBinanceExecPrice = 0.0
		sm.arbitrage.subStateFuturesExecQty = opts[2].(float64)
		sm.arbitrage.subStateFuturesExecPrice = opts[3].(float64)
	}
	sm.SubState = state

	return
}

func (sm *StateMachine) changeState2NotPosition() (err error) {
	sm.PositionState = PositionState_NotPosition

	sm.arbitrage.binanceLimitOrderId = 0
	sm.arbitrage.futuresLimitOrderId = 0
	sm.arbitrage.binanceAntiLimitOrderId = 0
	sm.arbitrage.futuresAntiLimitOrderId = 0
	sm.arbitrage.dPremiumStage = 0.0

	sm.arbitrage.subStateBinanceExecQty = 0.0
	sm.arbitrage.subStateBinanceExecPrice = 0.0
	sm.arbitrage.subStateFuturesExecQty = 0.0
	sm.arbitrage.subStateFuturesExecPrice = 0.0

	sm.arbitrage.symbolPosition = persistence.ArbitragePosition{}

	return
}

func (sm *StateMachine) changeState2Position(position persistence.ArbitragePosition) (err error) {
	sm.PositionState = PositionState_Position

	sm.arbitrage.dPremiumStage = 0.0

	sm.arbitrage.binanceLimitOrderId = 0
	sm.arbitrage.futuresLimitOrderId = 0
	sm.arbitrage.binanceAntiLimitOrderId = 0
	sm.arbitrage.futuresAntiLimitOrderId = 0

	sm.arbitrage.subStateBinanceExecQty = 0.0
	sm.arbitrage.subStateBinanceExecPrice = 0.0
	sm.arbitrage.subStateFuturesExecQty = 0.0
	sm.arbitrage.subStateFuturesExecPrice = 0.0

	if sm.State != State_OneCanClosePosition {
		sm.arbitrage.symbolPosition = position
	}

	// 持仓即返回
	sm.arbitrage.chanFinish <- struct{}{}
	return
}

func (sm *StateMachine) changeState2OneCanCreatePosition() (err error) {
	return
}

func (sm *StateMachine) changeState2LimitOrderCreated(binanceOrderId, futuresOrderId int64) (err error) {
	sm.arbitrage.binanceLimitOrderId = binanceOrderId
	sm.arbitrage.futuresLimitOrderId = futuresOrderId

	return
}

func (sm *StateMachine) changeState2AntiLimitOrderCreated(binanceOrderId, futuresOrderId int64) (err error) {
	sm.arbitrage.binanceLimitOrderId = binanceOrderId
	sm.arbitrage.futuresLimitOrderId = futuresOrderId

	return
}

func NewStateMachine(arbitrage *SymbolArbitrage) *StateMachine {
	sm := new(StateMachine)
	sm.PositionState = PositionState_Unknown
	sm.State = State_Unknow
	sm.SubState = SubState_Init
	sm.arbitrage = arbitrage

	return sm
}
